package com.hulk.ratel.config;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.StrSpliter;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import com.google.common.collect.Lists;
import com.hulk.ratel.config.properties.PropertyUtil;
import com.hulk.ratel.config.tenant.TenantContextHolder;
import com.hulk.ratel.persistence.handler.CommonMetaObjectHandler;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Profile;

import java.util.List;


/**
 * @author cmt
 *
 */
@Configuration
//@MapperScan(basePackages = { "com.hulk.ratel.persistence.mapper" })//这个注解，作用相当于下面的@Bean MapperScannerConfigurer，2者配置1份即可
public class MybatisPlusConfig {

	private static final String TENANT_ID_COLUMN = "tenant_id";
	private static final String[] IGNORE_TENANT_TABLES = new String[]{"t_tenant"};



	private String obtainTenantIdColumn() {
		String tenantIdColumn =	PropertyUtil.getProperty("tenantIdColumn");
		if(StrUtil.isEmpty(tenantIdColumn)) {
			return TENANT_ID_COLUMN;
		}else {
			return tenantIdColumn;
		}
	}

	private String[] obtainIgnoreTenantTables() {
		String  splitStr =	PropertyUtil.getProperty("ignoreTenantTables");
		List<String> ignoreTenantTables = StrSpliter.split(splitStr, ',', 0, true, true);
		if(CollUtil.isEmpty(ignoreTenantTables)) {
			return IGNORE_TENANT_TABLES;
		}else {
			String[] array = ignoreTenantTables.toArray(new String[ignoreTenantTables.size()]);
			return array;
		}
	}

	@Bean
	public MapperScannerConfigurer mapperScannerConfigurer() {
		MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
		scannerConfigurer.setBasePackage("com.hulk.ratel.persistence.mapper*");
		return scannerConfigurer;
	}

	/*
	 * 逻辑删除
	 */
	@Bean
	public ISqlInjector sqlInjector() {
		LogicSqlInjector logicSqlInjector =	new LogicSqlInjector();
		return logicSqlInjector;
	}

	/**
	 * mybatis-plus乐观锁插件
	 * 
	 */
	@Bean
	public OptimisticLockerInterceptor optimisticLockerInterceptor() {
		OptimisticLockerInterceptor lock = new OptimisticLockerInterceptor();
		return lock;
	}

	/**
	 * 自动填充
	 *
	 * @return
	 */
	@Bean
	public CommonMetaObjectHandler commonMetaObjectHandler() {
		return new CommonMetaObjectHandler();
	}




	/**
	 * SQL执行效率插件
	 */
	@Bean
	@Profile({"local","test"})// 设置 dev test 环境开启
	public PerformanceInterceptor performanceInterceptor() {
		PerformanceInterceptor page = new PerformanceInterceptor();
		page.setMaxTime(60000);
		page.setFormat(true);
		return page;
	}


	//SQL 执行分析拦截器【 目前只支持 MYSQL-5.6.3 以上版本 】，作用是分析 处理 DELETE UPDATE 语句， 防止小白或者恶意 delete update 全表操作！
	@Bean
    @Profile({"local","test"})// 设置 dev test 环境开启
	public SqlExplainInterceptor sqlExplainInterceptor() {
		SqlExplainInterceptor sql = new SqlExplainInterceptor();
		return sql;
	}



	/**
	 * 页插件，自动识别数据库类型
	 * 多租户属于 SQL 解析部分，依赖 MP 分页插件
	 */
	@Bean
	public PaginationInterceptor paginationInterceptor() {
		PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
		/*
		 * 【测试多租户】 SQL 解析处理拦截器<br>
		 * 这里固定写成住户 1 实际情况你可以从cookie读取，因此数据看不到 【 麻花藤 】 这条记录（ 注意观察 SQL ）<br>
		 */

		TenantSqlParser tenantSqlParser = new TenantSqlParser();
		tenantSqlParser.setTenantHandler(new TenantHandler() {

			@Override
			public Expression getTenantId() {

				// 从当前系统上下文中取出当前请求的租户ID，通过解析器注入到SQL中。
				Long currentTenantId = TenantContextHolder.getTenantId();
				if (null == currentTenantId) {
					throw new RuntimeException("#1129 getCurrentTenantId error.");
				}

				return new LongValue(currentTenantId);
			}

			@Override
			public String getTenantIdColumn() {
				return obtainTenantIdColumn();
			}

			@Override
			public boolean doTableFilter(String tableName) {
				// 这里可以判断是否过滤表
                /*if ("user".equals(tableName)) {
                    return true;
                }
				return false;
				*/
				// 忽略掉一些表：如租户表（TENANT）本身不需要执行这样的处理。
				return !ArrayUtil.contains(obtainIgnoreTenantTables(), tableName);
			}
		});

		paginationInterceptor.setSqlParserList(Lists.newArrayList(tenantSqlParser));
//        paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
//            @Override
//            public boolean doFilter(MetaObject metaObject) {
//                MappedStatement ms = PluginUtils.getMappedStatement(metaObject);
//                // 过滤自定义查询此时无租户信息约束【 麻花藤 】出现
//                if ("com.baomidou.springboot.mapper.UserMapper.selectListBySQL".equals(ms.getId())) {
//                    return true;
//                }
//                return false;
//            }
//        });
		return paginationInterceptor;
	}




	/**
	 * 自定义注入语句
	 *
	 * @return
	 */
//	@Bean
//	public MybatisPlusSqlInjector mybatisPlusSqlInjector() {
//		return new MybatisPlusSqlInjector();
//	}

}
